﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Weazel.Badger.Vhdl.Types
{
  public class Types
  {
    /// <summary>
    /// Create a new "type" object based on a typeid
    /// and a width.
    /// </summary>
    /// <param name="id">typeid of type to return</param>
    /// <param name="width">width of type to return</param>
    /// <returns></returns>
    public static Type CreateType(TypeId id, int width, bool ignoreTargetWidth)
    {
      if (id.name == "std_logic")
        return new StdLogic();
      else if (id.name == "std_logic_vector")
      {
        /*
        if (width == 1 && ignoreTargetWidth)
          return new StdLogic();
        else
        */
          return new StdLogicVector(width);
      }
      else if (id.name == "unsigned")
        return new Unsigned(width);
      else if (id.name == "signed")
        return new Signed(width);
      else if (id.name == "character")
        return new Character();
      else if (id.name == "integer")
        return new Integer(width);
      else if (id.name == "boolean")
        return new Weazel.Badger.Vhdl.Types.Boolean();
      else
        throw new NotSupportedException();
    }

    public static Conversion[] GetPossibleConversions(TypeId from)
    {
      if (from.name == "std_logic")
      {
        return new Conversion[] 
          {
            new Conversion(Types.StdLogic, Types.Character),
            new Conversion(Types.StdLogic, Types.StdLogic, ConversionProperties.Implicit)
          };
      }
      else if (from.name == "std_logic_vector")
      {
        return new Conversion[] 
          {
            new Conversion(Types.StdLogicVector, Types.Unsigned),
            new Conversion(Types.StdLogicVector, Types.Signed),
            new Conversion(Types.StdLogicVector, Types.Integer, ConversionProperties.WidthLost),
            new Conversion(Types.StdLogicVector, Types.StdLogicVector, ConversionProperties.Implicit | ConversionProperties.CanChangeWidth)
          };
      }
      else if (from.name == "unsigned")
      {
        return new Conversion[] 
          {
            new Conversion(Types.Unsigned, Types.Unsigned, ConversionProperties.Implicit),
            new Conversion(Types.Unsigned, Types.Signed),
            new Conversion(Types.Unsigned, Types.Integer, ConversionProperties.WidthLost),
            new Conversion(Types.Unsigned, Types.StdLogicVector, ConversionProperties.CanChangeWidth)
          };
      }
      else if (from.name == "signed")
      {
        return new Conversion[] 
          {
            new Conversion(Types.Signed, Types.Unsigned),
            new Conversion(Types.Signed, Types.Signed, ConversionProperties.Implicit),
            new Conversion(Types.Signed, Types.Integer, ConversionProperties.WidthLost),
            new Conversion(Types.Signed, Types.StdLogicVector, ConversionProperties.CanChangeWidth)
          };
      }
      else if (from.name == "integer")
      {
        return new Conversion[] 
          {
            new Conversion(Types.Integer, Types.Integer, ConversionProperties.Implicit),
            new Conversion(Types.Integer, Types.StdLogicVector, ConversionProperties.WidthRequired | ConversionProperties.CanChangeWidth)
          };
      }
      else if (from.name == "boolean")
      {
        return new Conversion[] 
          {
            new Conversion(Types.Boolean, Types.Boolean, ConversionProperties.Implicit)
          };
      }
      else if (from.name == "character")
      {
        return new Conversion[] 
          {
            new Conversion(Types.Character, Types.Character, ConversionProperties.Implicit)
          };
      }
      else
      {
        throw new NotSupportedException(from.name);
      }
    }

    public static readonly TypeId Undefined =
      new TypeId(
        0,
        "undefined"
    );

    public static readonly TypeId StdLogic = 
      new TypeId(
        1, 
        "std_logic"
      );

    public static readonly TypeId StdLogicVector = 
      new TypeId(
        2, 
        "std_logic_vector"
      );

    public static readonly TypeId Unsigned =
      new TypeId(
      3,
      "unsigned"
    );

    public static readonly TypeId Signed =
      new TypeId(
        4,
        "signed" 
      );

    public static readonly TypeId Integer = 
      new TypeId(
        5, 
        "integer"           
      );

    public static readonly TypeId Character =
      new TypeId(
        6,
        "character"
      );

    public static readonly TypeId Boolean = 
      new TypeId(
        7, 
        "boolean"
      );
  }
}
